package org.htmlparser.util;

import org.htmlparser.Node;

public class NodeTreeWalker
  implements NodeIterator
{
  protected Node mCurrentNode;
  protected boolean mDepthFirst;
  protected int mMaxDepth;
  protected Node mNextNode;
  protected Node mRootNode;

  public NodeTreeWalker(Node paramNode)
  {
    this(paramNode, true, -1);
  }

  public NodeTreeWalker(Node paramNode, boolean paramBoolean)
  {
    this(paramNode, paramBoolean, -1);
  }

  public NodeTreeWalker(Node paramNode, boolean paramBoolean, int paramInt)
  {
    if ((paramInt < 1) && (paramInt != -1))
      throw new IllegalArgumentException("Paramater maxDepth must be > 0 or equal to -1.");
    initRootNode(paramNode);
    this.mDepthFirst = paramBoolean;
    this.mMaxDepth = paramInt;
  }

  public Node getCurrentNode()
  {
    return this.mCurrentNode;
  }

  public int getCurrentNodeDepth()
  {
    int i = 0;
    if (this.mCurrentNode != null)
      for (Node localNode = this.mCurrentNode; localNode != this.mRootNode; localNode = localNode.getParent())
        ++i;
    return i;
  }

  public int getMaxDepth()
  {
    return this.mMaxDepth;
  }

  protected Node getNextNodeBreadthFirst()
  {
    Object localObject2;
    Node localNode1 = this.mCurrentNode.getNextSibling();
    if (localNode1 != null)
      localObject2 = localNode1;
    while (true)
    {
      while (true)
      {
        return localObject2;
        int i = getCurrentNodeDepth();
        Object localObject1 = this.mCurrentNode.getParent();
        int j = i - 1;
        do
        {
          Node localNode3;
          while (true)
          {
            if (j > 0)
            {
              while (true)
              {
                localNode3 = ((Node)localObject1).getNextSibling();
                if ((localNode3 != null) || (localObject1 == this.mRootNode))
                  break;
                localObject1 = ((Node)localObject1).getParent();
                --j;
              }
              if (localObject1 != this.mRootNode)
                break;
            }
            if ((this.mMaxDepth == -1) || (i < this.mMaxDepth))
              break label171;
            localObject2 = null;
          }
          localObject1 = localNode3;
        }
        while (localObject1 == null);
        NodeList localNodeList2 = ((Node)localObject1).getChildren();
        while (true)
        {
          while (true)
          {
            if ((localNodeList2 == null) || (localNodeList2.size() == 0));
            localObject1 = ((Node)localObject1).getFirstChild();
            if (++j != i)
              break;
            localObject2 = localObject1;
          }
          localNodeList2 = ((Node)localObject1).getChildren();
        }
        label171: Node localNode2 = this.mRootNode.getFirstChild();
        int k = i + 1;
        int l = 1;
        do
        {
          if (l <= 0)
            break label309;
          NodeList localNodeList1 = localNode2.getChildren();
          while (true)
          {
            while (true)
            {
              if ((localNodeList1 == null) || (localNodeList1.size() == 0))
                break label255;
              localNode2 = localNode2.getFirstChild();
              if (++l != k)
                break;
              localObject2 = localNode2;
            }
            localNodeList1 = localNode2.getChildren();
          }
          while ((localNode2.getNextSibling() == null) && (localNode2 != this.mRootNode))
          {
            label255: localNode2 = localNode2.getParent();
            --l;
          }
          localNode2 = localNode2.getNextSibling();
        }
        while (localNode2 != null);
        localObject2 = null;
      }
      label309: localObject2 = null;
    }
  }

  protected Node getNextNodeDepthFirst()
  {
    Object localObject;
    int i = getCurrentNodeDepth();
    if ((this.mMaxDepth == -1) || (i < this.mMaxDepth))
    {
      Node localNode1 = this.mCurrentNode.getFirstChild();
      if (localNode1 != null)
        localObject = localNode1;
    }
    while (true)
    {
      return localObject;
      Node localNode2 = this.mCurrentNode;
      Node localNode3 = null;
      while (localNode2 != this.mRootNode)
      {
        localNode3 = localNode2.getNextSibling();
        if (localNode3 != null)
          break;
        localNode2 = localNode2.getParent();
      }
      localObject = localNode3;
    }
  }

  public Node getRootNode()
  {
    return this.mRootNode;
  }

  public boolean hasMoreNodes()
  {
    int i;
    if (this.mNextNode == null)
    {
      if (this.mCurrentNode != null)
        break label38;
      this.mNextNode = this.mRootNode.getFirstChild();
    }
    if (this.mNextNode != null)
      i = 1;
    while (true)
    {
      while (true)
      {
        while (true)
        {
          return i;
          label38: if (!(this.mDepthFirst))
            break;
          this.mNextNode = getNextNodeDepthFirst();
        }
        this.mNextNode = getNextNodeBreadthFirst();
      }
      i = 0;
    }
  }

  protected void initRootNode(Node paramNode)
    throws NullPointerException
  {
    if (paramNode == null)
      throw new NullPointerException("Root Node cannot be null.");
    this.mRootNode = paramNode;
    this.mCurrentNode = null;
    this.mNextNode = null;
  }

  public boolean isDepthFirst()
  {
    return this.mDepthFirst;
  }

  public Node nextNode()
  {
    if (this.mNextNode != null)
    {
      this.mCurrentNode = this.mNextNode;
      this.mNextNode = null;
    }
    while (true)
    {
      while (true)
      {
        while (true)
        {
          return this.mCurrentNode;
          if (this.mCurrentNode != null)
            break;
          this.mCurrentNode = this.mRootNode.getFirstChild();
        }
        if (!(this.mDepthFirst))
          break;
        this.mCurrentNode = getNextNodeDepthFirst();
      }
      this.mCurrentNode = getNextNodeBreadthFirst();
    }
  }

  public void removeMaxDepthRestriction()
  {
    this.mMaxDepth = -1;
  }

  public void reset()
  {
    this.mCurrentNode = null;
    this.mNextNode = null;
  }

  public void setCurrentNodeAsRootNode()
    throws NullPointerException
  {
    if (this.mCurrentNode == null)
      throw new NullPointerException("Current Node is null, cannot set as root Node.");
    initRootNode(this.mCurrentNode);
  }

  public void setDepthFirst(boolean paramBoolean)
  {
    if (this.mDepthFirst != paramBoolean)
      this.mNextNode = null;
    this.mDepthFirst = paramBoolean;
  }

  public void setRootNode(Node paramNode)
    throws NullPointerException
  {
    initRootNode(paramNode);
  }
}